﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ComponentAce.Compression.ZipForge;
using CRC32c;

namespace APBR_Patch_Mirror
{
    public partial class MainForm : Form
    {
        public static string report = "0";
        public static string Progname = "APB Repair - 1.3.0" + " (Build " + ProgUpdater.version + ") ";
        public MainForm()
        {
            CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            //this.BringToFront();
            beginTasks();
        }

        async void beginTasks()
        {
            WriteToView(await new WebClient().DownloadStringTaskAsync("http://apbcorner.com/APB_Reloaded/APB_Repair/news.txt"));
            await iUpdate();
        }

        async Task iUpdate()
        {
            try
            {
                Runtime();
                while (File.Exists("APB Repair.bak")) { try { File.Delete("APB Repair.bak"); } catch { } }
                this.Text = Progname + ProgUpdater.buildDate;
                int verify = Int16.Parse(new WebClient().DownloadString("http://apbcorner.com/APB_Reloaded/APB_Repair/Version.php"));
                if (ProgUpdater.version != verify) { Application.Run(new ProgUpdater()); }
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
            }
        }
                
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Environment.Exit(-1);
        }

        private void Fixet_Click(object sender, EventArgs e)
        {
            Fixet.Enabled = false;
            LogView.Clear();
            CheckAPBR();
        }

        private void SubmitError(string error)
        {
            if (report == "1")
            {
                string ipaddress;
                File.AppendAllText(Sanity.log, error + Environment.NewLine);
                WebRequest request = WebRequest.Create("http://checkip.dyndns.org/");
                WebResponse response = request.GetResponse();
                StreamReader stream = new StreamReader(response.GetResponseStream());
                ipaddress = stream.ReadToEnd(); stream.Close(); response.Close();
                int first = ipaddress.IndexOf("Address: ") + 9;
                int last = ipaddress.LastIndexOf("</body>");
                ipaddress = ipaddress.Substring(first, last - first);

                MailMessage mail = new MailMessage();
                SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com");
                mail.From = new MailAddress("apbcorner@gmail.com");
                mail.To.Add("jaredt741@gmail.com");
                mail.Subject = "Error Report From: " + ipaddress;
                mail.Body = "IPAddress: " + ipaddress + "\n\n" + "Program Version: " + ProgUpdater.version + "\n\n" + error;

                System.Net.Mail.Attachment attachment;
                //try { attachment = new System.Net.Mail.Attachment(Sanity.log); } catch { }
                //mail.Attachments.Add(attachment);

                SmtpServer.Port = 587;
                SmtpServer.Credentials = new System.Net.NetworkCredential("apbcorner@gmail.com", "admins12");
                SmtpServer.EnableSsl = true;
                SmtpServer.Send(mail);

                MessageBox.Show(error + "\n\n\n An error report has been sent");
                Environment.Exit(-1);
            }
            else
            {
                MessageBox.Show(error + "\n\nError reporting is off. \n\nShutting down due to Unhandled Exception.");
                Environment.Exit(-1);
            }
        }
        
        public async Task Runtime()
        {
            Program.loadasm();
            await GetMirrors();
            await StartCheck();
            await CheckMirrors();
            Launcher = new read.LauncherSyncer(def.launcher);
            Client = new read.ClientSyncer(def.client);
        }

        public async void WriteToView(string text)
        {
            if (InvokeRequired)
            {
                Invoke((Action<string>)WriteToView, text);
            }
            else
            {
                LogView.AppendText(text+"\n");
                LogView.ScrollToCaret();
            }
        }

        public async void WriteToDL(string text)
        {
            string[] test = text.Split('\\', '/', '\"');
            string test2 = test[test.Length - 1];
            if (InvokeRequired)
            {
                Invoke((Action<string>)WriteToDL, test2);
            }
            else
            {
                DLlog.AppendText(test2 + "\n");
                DLlog.ScrollToCaret();
            }
        }

        public async Task CheckAPBR()
        {
            WriteToView("Checking APB: Reloaded Install...  ");
            try
            {
                for (i = 0; i < Launcher._LauncherFiles.Count; i++)
                {
                    progressBar1.Maximum = Launcher._LauncherFiles.Count;
                    progressBar1.Value = i;
                    filePath = Path.GetFullPath(Launcher._LauncherFiles[i].FileName);
                    WriteToView("\"" + Launcher._LauncherFiles[i].FileName + "\"......");
                    if (File.Exists(filePath))
                    {
                        Crc32 crc32 = new Crc32();
                        using (FileStream f = File.Open(filePath, FileMode.Open)) crc32.ComputeHash(f);
                        long crc = crc32.CrcValue;
                        if (crc != Launcher._LauncherFiles[i].Crc)
                        {
                            Download(Launcher._LauncherFiles);
                        }
                        Sanity.CheckLauncher(filePath);
                    }
                    else
                    {
                        Download(Launcher._LauncherFiles);
                        Sanity.CheckLauncher(filePath);
                    }
                }
                progressBar1.Value = 0;

                for (i = 0; i < Client._ClientFiles.Count; i++)
                {
                    progressBar1.Maximum = Client._ClientFiles.Count;
                    progressBar1.Value = i;
                    filePath = Path.GetFullPath(Client._ClientFiles[i].FileName);
                    WriteToView("\"" + Client._ClientFiles[i].FileName + "\"......");
                    if (File.Exists(filePath))
                    {
                        Crc32 crc32 = new Crc32();
                        using (FileStream f = File.Open(filePath, FileMode.Open)) crc32.ComputeHash(f);
                        long crc = crc32.CrcValue;
                        if (crc != Client._ClientFiles[i].Crc)
                        {
                            Download(Client._ClientFiles);
                        }
                        Sanity.CheckClient(filePath);
                    }
                    else
                    {
                        Download(Client._ClientFiles);
                        Sanity.CheckClient(filePath);
                    }
                }
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
                MessageBox.Show(e.ToString() +"\n\n\n An error report has been sent");
                File.AppendAllText(Sanity.log, Sanity.time + "    " + e.ToString() + "\r\n");
                Environment.Exit(-1);
            }
            progressBar1.Value = 0;
            Fixet.Enabled = true;
        }

        public async Task file(string url, string saveAs)
        {
            try
            {
                Extracting = saveAs;
                try
                {
                    File.AppendAllText(Sanity.log, Sanity.time + "    Downloading:" + "" + saveAs + "   Size:" +
                    Launcher._LauncherFiles[i].Size + "   CRC:" + Launcher._LauncherFiles[i].Crc + Environment.NewLine);
                }
                catch { }
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.UserAgent = APBR_Patch_Mirror.MainForm.Progname;
                byte[] buffer = new byte[1000];
                WriteToDL("" + saveAs + "");
                using (WebResponse response = request.GetResponse())
                {
                    using (Stream responseStream = response.GetResponseStream())
                    {
                        using (MemoryStream memoryStream = new MemoryStream())
                        {
                            int count;
                            do
                            {
                                count = responseStream.Read(buffer, 0, buffer.Length);
                                DLbar.Maximum = Convert.ToInt32(response.ContentLength);
                                if ((DLbar.Value + count) <= DLbar.Maximum) { DLbar.Value += count; }
                                else { DLbar.Value = DLbar.Maximum; }

                                memoryStream.Write(buffer, 0, count);

                            } while (count != 0);
                            byte[] result = memoryStream.ToArray();
                            File.WriteAllBytes(saveAs, result);
                            Thread.Sleep(50);
                            DLbar.Value = 0;
                        }
                    }
                }
                if (saveAs.EndsWith(".zip"))
                { Extract(saveAs); }
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
            }   
            progressBar1.Value = 0;
        }

        public async Task Download(List<APBR_Patch_Mirror.read.FileDefinition> listDefinition)
        {
            try
            {
                int numGen = new Random().Next(0, Webmirrors.Length);
                gmir = Webmirrors[numGen].ToString();
                string dir = Directory.GetCurrentDirectory() + "\\";
                var get = listDefinition[i].FileName;
                Directory.CreateDirectory(Path.GetDirectoryName(filePath));
                if (Webmirrors[numGen] == "http://apb.patch.gamersfirst.com/")
                {
                    string RemoteFile = Webmirrors[numGen].ToString() + "Launcher" + launcherversion + "\\" + get + ".zip";
                    file(RemoteFile, get + ".zip");
                }
                else
                {
                    string RemoteFile = Webmirrors[numGen].ToString() + get;
                    file(RemoteFile, get);
                }
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
            }
        }

        public async Task Extract(string filename)
        {
            try
            {
                ZipForge archiver = new ZipForge();
                archiver.FileName = filename;
                archiver.OpenArchive();
                archiver.BaseDir = Directory.GetCurrentDirectory();
                if (Extracting == "Client" + clientversion + ".xml.zip")
                { archiver.RenameFile("Client" + clientversion + ".xml", "ClientFiles.xml"); }
                if (Extracting == "Launcher" + launcherversion + ".xml.zip")
                { archiver.RenameFile("Launcher" + launcherversion + ".xml", "LauncherFiles.xml"); }

                archiver.DeleteFiles("*.sig");
                archiver.ExtractFiles("*");
                archiver.CloseArchive();
                System.Threading.Thread.Sleep(1);
                File.Delete(filename);
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
            }
        }

        public async Task GetMirrors()
        {
            if (File.Exists("Launcher" + launcherversion + ".xml" + ".zip")) { File.Delete("Launcher" + launcherversion + ".xml" + ".zip"); }
            if (File.Exists("Client" + clientversion + ".xml" + ".zip")) { File.Delete("Client" + clientversion + ".xml" + ".zip"); }
            try
            {
                string temp = new WebClient().DownloadString("http://apbcorner.com/APB_Reloaded/APB_Repair/Mirrors.php");
                Webmirrors = temp.Split('\n');
                //WriteToView(Webmirrors.Length + " Mirrors loaded.");
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
            }   
        }

        public async Task CheckMirrors()
        {
            try
            {
                for (int interger = 0; interger < Webmirrors.Length; interger++)
                {
                    try
                    {
                        WebClient webClient = new WebClient();
                        webClient.DownloadData(Webmirrors[interger].ToString() + "Patches.xml");
                        WriteToView("Mirror " + Webmirrors[interger].ToString() + " returned OK.");
                        webClient.Dispose();
                    }
                    catch (Exception e)
                    {
                        WriteToView("\nMirror " + Webmirrors[interger].ToString() + " returned ERROR.");
                        WriteToView("Program will not work propperly until the problematic mirrors are fixed!!");
                        WriteToView("Contact a developer for assistance.");
                        SubmitError(e.ToString());
                    }
                }
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
            }   
        }

        public async Task StartCheck()
        {
            try
            {
                string dstring = new WebClient().DownloadString(def.patchurl + def.patches);
                char[] delimiterChars = { '"' };
                string[] words = dstring.Split(delimiterChars);
                clientversion = words[11];
                launcherversion = words[7];
                new WebClient().DownloadFile(def.patchurl + def.patches, def.patches);
                if (File.Exists(def.patches) == true & File.Exists(def.client) == true & File.Exists(def.launcher) == true)
                {
                    read.XML("ClientFiles.xml", def.clientver, 2);
                    if (def.clientver == clientversion)
                    {
                        WriteToView("Checking Client Version " + def.clientver + "... VALID");
                    }
                    else
                    {
                        WriteToView("Checking Client Version... INVALID");
                        file(def.patchurl + "Client" + clientversion + ".xml.zip", "Client" + clientversion + ".xml.zip");
                    }

                    read.XML2("LauncherFiles.xml", def.launcherver, 2);
                    if (def.launcherver == launcherversion)
                    {
                        WriteToView("Checking Launcher Version " + def.launcherver + "... VALID");
                    }
                    else
                    {
                        WriteToView("Checking Launcher Version... INVALID");
                        file(def.patchurl + "Launcher" + launcherversion + ".xml.zip", "Launcher" + launcherversion + ".xml.zip");
                    }
                }
                else
                {
                    if (File.Exists(def.patches) == false)
                    {
                        WriteToView(def.patches + " is missing... Attempting to retrieve");
                        file(G1 + def.patches, def.patches);
                    }
                    read.XML(def.patches, def.clientver, 8);
                    if (File.Exists(def.client) == false)
                    {
                        WriteToView(def.client + " is missing... Attempting to retrieve");
                        file(G1 + "Client" + clientversion + ".xml.zip", "Client" + clientversion + ".xml.zip");
                    }
                    read.XML2(def.patches, def.launcherver, 8);
                    if (File.Exists(def.launcher) == false)
                    {
                        WriteToView(def.launcher + " is missing... Attempting to retrieve");
                        file(G1 + "Launcher" + launcherversion + ".xml.zip", "Launcher" + launcherversion + ".xml.zip");
                    }
                    StartCheck();
                }
            }
            catch (Exception e)
            {
                SubmitError(e.ToString());
                MessageBox.Show(e.ToString() + "\n\n\n An error report has been sent");
                File.AppendAllText(Sanity.log, e.ToString() + Environment.NewLine);
                Environment.Exit(-1);
            }
        }

        public static int i = 0;
        public static read.LauncherSyncer Launcher;
        public static read.ClientSyncer Client;
        public static string filePath = "";
        public static string gmir = null;
        public static string Extracting = null;
        public static string cver = "Client" + clientversion + ".xml";
        public static string lver = "Launcher" + launcherversion + ".xml";
        public static string[] Webmirrors = null;
        public static string G1 = "http://apb.patch.gamersfirst.com/";
        public static string clientversion = null;
        public static string launcherversion = null;
    }
}